<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BOnlineQueueDbAdapter
 *
 * @author ID59C
 */
class BOnlineQueueDbAdapter extends BDbAdapter {

    const Allocate_Queue_Strategy_On_Cycle = "allocateQueueOnCycle";
    const Allocate_Queue_Strategy_On_TimeSlot = "allocateQueueOnTimeSlot";
    const Process_Queue_Status_Start = "process_queue_start";
    const Process_Queue_Status_End = "process_queue_end";

    //put your code here
    public function getConnection() {
        $dsn = 'mysql:host=bieleenAppDb.db.10608480.hostedresource.com;dbname=bieleenAppDb';
        $userName = 'bieleenAppDb';
        $password = 'Wang69@AppDb';

        $conn = new CDbConnection($dsn, $userName, $password);
        $conn->emulatePrepare = TRUE;
        $conn->charset = 'utf8';
        //$conn->active = TRUE;
        return $conn;
    }

    public function addServiceQueueLine($service, $name, $description = NULL) {
        $qlModel = new BMAppOnlineQueueQueueLine();
        $qlModel->name = $name;
        if ($description != NULL)
            $qlModel->description = $description;

        $qlModel->save();

        $sqlModel = new BMAppOnlineQueueServiceQueueLine();
        $sqlModel->service_id = $service->getId();
        $sqlModel->queueline_id = $qlModel->_id;

        $sqlModel->save();

        return $sqlModel->_id;
    }

    public function addServiceQueueLineResource($sQueueLineId, $service, $name, $queueMax = NULL, $description = NULL) {
        $sResource = new BMAppOnlineQueueServiceResource();

        if ($description != NULL)
            $sResource->description = $description;

        $sResource->service_id = $service->getId();
        $sResource->name = $name;
        $sResource->save();

        $resourceId = $sResource->_id;

        $ql_sResource = new BMServiceQueueLineResource();
        $ql_sResource->service_queueline_id = $sQueueLineId;
        $ql_sResource->service_resource_id = $resourceId;
        $ql_sResource->save();

        if ($queueMax != NULL) {
            $queueMaxModel = new BMServiceQueueLineResourceMax();
            $queueMaxModel->maxqueuenumber = $queueMax;
            $queueMaxModel->service_queueline_resource_id = $resourceId;
            $queueMaxModel->save();
        }

        return $ql_sResource->_id;
    }

    public function addQueueLineTimeResource($data) {
        //$serviceQueueLineId, $cyclePeriodExpress = NULL, $allocateQueueStrategy = null, $timeSlotLength = 1, $timeSlotPeriod = NULL, $startTime = null, $endTime = null, $cycleLength = NULL, $cycleRepeatTime = NULL) {

        $cyclePeriod = array();
        $period = array();
        $timePieces = array();

        $cyclePeriodExpression = $data['cycleLength'];

        if ($cyclePeriodExpression != NULL) {
            $this->parsePeriodExpression($cyclePeriodExpression, $period);
            $this->parsePeriodIntoPieces($period, $timePieces);
            $cyclePeriod['expression'] = $cyclePeriodExpression;
            $cyclePeriod['period'] = $period;
            //length format like '1 day', '3 week'
            //$cyclePeriod['length'] = isset($period['unit']) ? (isset($period['length']) ? $period['length'] . ' ' . $period['unit'] : '1 ' . $period['unit']) : NULL;
            $cyclePeriod['length'] = $this->parsePeriodLength($period);
            $cyclePeriod['timePieces'] = $timePieces;
        }

        $timeSlotPeriod = array();
        $period = array();

        $timeSlotPeriodExpression = $data['timeSlotLength'];

        if ($timeSlotPeriodExpression != NULL) {
            $timePieces = array();
            $this->parsePeriodExpression($timeSlotPeriodExpression, $period);
            $this->parsePeriodIntoPieces($period, $timePieces);
            $timeSlotPeriod['expression'] = $timeSlotPeriodExpression;
            $timeSlotPeriod['period'] = $period;
            $timeSlotPeriod['length'] = $this->parsePeriodLength($period);
        }

        $makeQueuePeriod = array();
        $period = array();

        $makeQueuePeriodExpression = $data['makeQueueCycleLength'];

        if ($makeQueuePeriodExpression != NULL) {
            $timePieces = array();
            $this->parsePeriodExpression($makeQueuePeriodExpression, $period);
            $this->parsePeriodIntoPieces($period, $timePieces);
            $makeQueuePeriod['expression'] = $makeQueuePeriodExpression;
            $makeQueuePeriod['period'] = $period;
            $makeQueuePeriod['length'] = $this->parsePeriodLength($period);
        }

        $processQueuePeriod = array();
        $period = array();

        $processQueuePeriodExpression = $data['processQueueCycleLength'];

        if ($processQueuePeriodExpression != NULL) {
            $timePieces = array();
            $this->parsePeriodExpression($processQueuePeriodExpression, $period);
            $this->parsePeriodIntoPieces($period, $timePieces);
            $processQueuePeriod['expression'] = $processQueuePeriodExpression;
            $processQueuePeriod['period'] = $period;
            $processQueuePeriod['length'] = $this->parsePeriodLength($period);
        }

        //populate timeResoure startTime and endTime
        $trStartTime = NULL;
        $trEndTime = null;
        $trLength = null;
        $cycleRepreatTimes = 1;
        if (isset($data['startTime']) && $data['startTime'] != NULL) {
            $trStartTime = strtotime($data['startTime']);
          //  $trStartTime = $trStartTime < time() ? time() : $trStartTime;

            if (isset($cyclePeriod['period'])) {
                $cycleRepreatTimes = 1;
                $cyclePeriodLength = isset($cyclePeriod['period']['length']) ? $cyclePeriod['period']['length'] : 1;
                if (isset($data['cycleRepeatTime']) && $data['cycleRepeatTime'] != NULL) {
                    if ($data['cycleRepeatTime'] != '0')
                        $cycleRepreatTimes = intval($data['cycleRepeatTime']);
                }

                if (isset($cyclePeriod['period']['unit'])) {
                    $trLengthValue = $cyclePeriodLength * $cycleRepreatTimes;
                    if ($trLengthValue > 1)
                        $trLength = $trLengthValue . $cyclePeriod['period']['unit'] . 's';
                    if ($trLengthValue == 1)
                        $trLength = $trLengthValue . $cyclePeriod['period']['unit'];
                    $trEndTime = strtotime('+' . $trLength, $trStartTime);
                }
            }
        }
        if (isset($data['endTime']) && $data['endTime'] != NULL) {
            $trEndTime = strtotime($data['endTime']);
            $cycleLength = NULL;

            if (isset($cyclePeriod['period'])) {
                $cyclePeriodLength = isset($cyclePeriod['period']['length']) ? $cyclePeriod['period']['length'] : 1;
                if (isset($data['cycleRepeatTime']) && $data['cycleRepeatTime'] != NULL) {
                    $cycleRepreatTimes = intval($data['cycleRepeatTime']);
                } else {
                    $cycleRepreatTimes = 1;
                }

                $cycleRepreatTimes = $cycleRepreatTimes == 0 ? 1 : $cycleRepreatTimes;
                //     $cyclePeriodLength = isset($cyclePeriod['period']['length']) ? $cyclePeriod['period']['length'] : 1;
                //         if (isset($data['startTime']) && $data['startTime'] != NULL) {               

                if (isset($cyclePeriod['period']['unit'])) {
                    if ($cyclePeriodLength > 1) {
                        $cycleLength = $cyclePeriodLength . $cyclePeriod['period']['unit'] . 's';
                    }
                    if ($cyclePeriodLength == 1) {
                        $cycleLength = $cyclePeriodLength . $cyclePeriod['period']['unit'];
                    }
                    $trLengthValue = $cyclePeriodLength * $cycleRepreatTimes;
                    if ($trLengthValue > 1)
                        $trLength = $trLengthValue . $cyclePeriod['period']['unit'] . 's';
                    if ($trLengthValue == 1)
                        $trLength = $trLengthValue . $cyclePeriod['period']['unit'];
                    $trStartTime = strtotime('-' . $trLength, $trEndTime);
                }

                //if set starttime or not set starttime, it will populate repeat times and base on starttime
                $startTime = isset($data['startTime']) && $data['startTime'] != NULL ? strtotime($data['startTime']) : time();
                $startTime = $startTime < time() ? time() : $startTime;
                $i = 0;
                $endTime = strtotime($data['endTime']);
                $timeIntervalLength = $cyclePeriodLength > 1 ? $cyclePeriodLength . ' ' . $cyclePeriod['period']['unit'] . 's' : $cyclePeriodLength . ' ' . $cyclePeriod['period']['unit'];
                while (true) {
                    $i++;
                    $tempStartTime = $this->subTimeInterval($endTime, $timeIntervalLength, $i);
                    if ($tempStartTime < $startTime) {
                        $cycleRepreatTimes = $i;
                        $trStartTime = $tempStartTime;
                        break;
                    }
                }
            }
        }

        $timeResource = new BMServiceQueueLineTimeResource();
        $timeResource->service_queueline_id = $data['serviceQueueLineId'];
        $timeResource->allocate_queue_strategy = $data['allocateQueueStrategy'];
        $timeResource->start_time = $trStartTime;
        $timeResource->end_time = $trEndTime;

        $timeResource->cycle_length = $cyclePeriod['length'];
        $timeResource->cycle_repeat_times = $cycleRepreatTimes;
        $timeResource->cycle_period = $cyclePeriod == NULL ? NULL : serialize($cyclePeriod);

        $timeResource->timeslot_length = isset($timeSlotPeriod['length']) ? $timeSlotPeriod['length'] : NULL;
        //$timeResource->timeslot_period = $timeSlotPeriod;

        $timeResource->makequeue_cycle_length = isset($makeQueuePeriod['length']) ? $makeQueuePeriod['length'] : NULL;
        $timeResource->makequeue_offset_to_endtime = isset($data['makeQueueCycleOffset']) ? $data['makeQueueCycleOffset'] : 0;
        $timeResource->makequeue_cycle_period = $makeQueuePeriod == NULL ? NULL : serialize($makeQueuePeriod);

        $timeResource->processqueue_cycle_length = isset($processQueuePeriod['length']) ? $processQueuePeriod['length'] : NULL;
        $timeResource->processqueue_offset_to_endtime = isset($data['processQueueCycleOffset']) ? $data['processQueueCycleOffset'] : 0;
        $timeResource->processqueue_cycle_period = $processQueuePeriod == NULL ? NULL : serialize($processQueuePeriod);
        $timeResource->save();

        return $timeResource->_id;
    }

    public function addQueueLineChild($parentId, $childId) {
        $ql_childModel = new BMServiceQueueLineChild();
        $ql_childModel->parent_id = $parentId;
        $ql_childModel->child_id = $childId;
        $ql_childModel->save();
    }

    /**
     * add transaction is actived when add queue is run at first time
     * @param type $resourceId
     * @param type $startTime
     * @param type $endTime
     * @param type $sequence
     */
    public function addQueueLineTransaction($resourceId, $startTime = null, $endTime = null, $sequence = NULL, $timeSlotLength = NULL) {

        $transactionModel = new BMServiceQueueLineTransaction();
        $transactionModel->service_queueline_resource_id = $resourceId;
        $transactionModel->start_time = $startTime;
        $transactionModel->end_time = $endTime;
        $transactionModel->transaction_sequence = $sequence;
        $transactionModel->transaction_status = 'active';

        $transactionModel->save();

        $qlResource = BMServiceQueueLineResource::model()->findByAttributes(array('service_resource_id' => $resourceId));
        $serviceQueueLineId = $qlResource->service_queueline_id;

        $timeResource = BMServiceQueueLineTimeResource::model()->findByAttributes(array('service_queueline_id' => $serviceQueueLineId));
        $intTransLength = $this->parsePeriodLength($timeResource->cycle_length);
        $intTimeSlotLength = $this->parsePeriodLength($timeSlotLength);

        $transEndTime = $endTime;

        if ($timeResource->allocate_queue_strategy == self::Allocate_Queue_Strategy_On_TimeSlot) {
            $timeSlotCount = $intTransLength / $intTimeSlotLength;
            for ($i = 0; $i < $timeSlotCount; $i++) {
                $timeSlotEndTime = $this->subTimeInterval($transEndTime, $timeSlotLength, $timeSlotCount - 1 - $i);
                $this->addTransactionTimeSlots($transactionModel->_id, $i, $timeSlotEndTime, $timeSlotLength);
            }
        }

        return $transactionModel;
    }

    protected function addTransactionTimeSlots($transId, $sequence, $endTime, $timeSlotLength) {

        $transTimeSlot = new BMServiceQueueLineTransactionTimeSlot();

        $transTimeSlot->timeslot_end_time = $endTime;
        $transTimeSlot->timeslot_length = $timeSlotLength;
        $transTimeSlot->timeslot_sequence = $sequence;
        $transTimeSlot->transaction_id = $transId;

        $transTimeSlot->save();
    }

    public function makeTransactionQueue($queueLine, $makeQueueTime, $resource = array(), $timeResource = array(), $queueMaker = array()) {
        $queueLineId = isset($queueLine['id']) ? $queueLine['id'] : NULL;
        //$resourceId = isset($resource['id']) ? $resource['id'] : NULL;
        //$timeResourceId = isset($timeResource['id']) ? $timeResource['id'] : NULL;
        $timeSlotList = isset($timeResource['timeSlotList']) ? $timeResource['timeSlotList'] : array();

        $timeResourceModel = BMServiceQueueLineTimeResource::model()->findByAttributes(array('service_queueline_id' => $queueLineId));
        $allocateStrategy = $timeResourceModel->allocate_queue_strategy;

        if ($allocateStrategy == self::Allocate_Queue_Strategy_On_Cycle) {
            $newTransQueueModel = $this->addTransactionQueue($queueLine, $makeQueueTime, $resource, $timeResource, $queueMaker);
            foreach ($timeSlotList as $timeSlot) {
                $sql = "select max(queue_number_in_timeslot) from bln_app_onlinequeue_service_queueline_transaction_timeslot_queue where 
                    transaction_timeslot_id = :TimeSlotId";
                $params = array(':TimeSlotId' => $timeSlot['id']);
                $maxTimeSlotId = BMServiceQueueLineTransactionTimeSlot::model()->findBySql($sql, $params);
                $timeSlotQueueModel = new BMServiceQueueLineTransactionTimeSlotQueue();
                $timeSlotQueueModel->queue_number_in_timeslot = $maxTimeSlotId + 1;
                $timeSlotQueueModel->transaction_queue_id = $newTransQueueModel->_id;
                $timeSlotQueueModel->transaction_timeslot_id = $timeSlot['id'];
                $timeSlotQueueModel->save();
            }
        }

        if ($allocateStrategy == self::Allocate_Queue_Strategy_On_TimeSlot) {
            foreach ($timeSlotList as $timeSlot) {
                $newTransQueueModel = $this->addTransactionQueue($queueLine, $makeQueueTime, $resource, $timeResource, $queueMaker);
                $sql = "select max(queue_number_in_timeslot) from bln_app_onlinequeue_service_queueline_transaction_timeslot_queue where 
                    transaction_timeslot_id = :TimeSlotId";
                $params = array(':TimeSlotId' => $timeSlot['id']);
                $maxTimeSlotId = BMServiceQueueLineTransactionTimeSlot::model()->findBySql($sql, $params);
                $timeSlotQueueModel = new BMServiceQueueLineTransactionTimeSlotQueue();
                $timeSlotQueueModel->queue_number_in_timeslot = $maxTimeSlotId + 1;
                $timeSlotQueueModel->transaction_queue_id = $newTransQueueModel->_id;
                $timeSlotQueueModel->transaction_timeslot_id = $timeSlot['id'];
                $timeSlotQueueModel->save();
            }
        }
    }

    public function processTransactionQueue($queueNumber, $processTime, $queueProcessor = array(), $transaction = array()) {
        $tranQueue = BMServiceQueueLineTransactionQueue::model()->findByAttributes(
                array('queue_number' => $queueNumber, 'transaction_id' => $transaction['id']));

        $processStartTime = isset($processTime['startTime']) ? $processTime['startTime'] : NULL;
        $processEndTime = isset($processTime['endTime']) ? $processTime['endTime'] : NULL;

        $processStatus = '';

        if ($processStartTime != NULL) {
            $processStatus = self::Process_Queue_Status_Start;
        }

        if ($processEndTime != NULL) {
            $processStatus = self::Process_Queue_Status_End;
        }

        $tranQueue->processqueue_status = $processStatus;
        $tranQueue->data['processQueueTime'] = $processTime;
        $tranQueue->queue_admin_id = $queueProcessor['id'];

        $tranQueue->save();

        return $tranQueue;
    }

    /**
     * this function will search transaction by some condition, if do not find can create new base on condition
     * for example, when reach make queue time, it will create new if no transaction exist
     * @param type $queueLine
     * @param type $resource
     * @param type $timeResource
     * @param type $triggerTime
     * @return type
     */
    public function findTransaction($queueLine, $resources = array(), $triggerTime = NULL, $timeResource = array()) {

        $makeQueueTime = isset($triggerTime['makeQueueTime']) ? $triggerTime['makeQueueTime'] : NULL;
        $processQueueTime = isset($triggerTime['processQueueTime']) ? $triggerTime['processQueueTime'] : NULL;
        $queueLineId = isset($queueLine['id']) ? $queueLine['id'] : NULL;

        //$resourceId = ($resource instanceof BAQResource) ? $resource->id : NULL;
        //$timeResourceId = isset($timeResource['id']) ? $timeResource['id'] : NULL;

        $timeResourceModel = BMServiceQueueLineTimeResource::model()->findByAttributes(array('service_queueline_id' => $queueLineId));

        $currentCycle = array();
        $transaction = NULL;
        $activeCycles = array();
        $activeTransactions = array();
        $repeatTimes = 1;

        if ($timeResourceModel != NULL) {
            $trStartTime = $timeResourceModel->start_time;
            $trEndTime = $timeResourceModel->end_time;
            $trCycleLength = $timeResourceModel->cycle_length;
            $makeQueueCycleLength = $timeResourceModel->makequeue_cycle_length;
            if ($makeQueueCycleLength == NULL)
                $makeQueueCycleLength = $trCycleLength;
            $makeQueueOffsetToEnd = $timeResourceModel->makequeue_offset_to_endtime;
            if ($makeQueueOffsetToEnd == NULL)
                $makeQueueOffsetToEnd = 0;
            $processQueueCycleLength = $timeResourceModel->processqueue_cycle_length;
            if ($processQueueCycleLength == NULL)
                $processQueueCycleLength = $trCycleLength;
            $processQueueOffsetToEnd = $timeResourceModel->processqueue_offset_to_endtime;
            if ($processQueueOffsetToEnd == NULL)
                $processQueueOffsetToEnd = 0;
            $repeatTimes = $timeResourceModel->cycle_repeat_times;
            if ($repeatTimes == 0)
                $repeatTimes = 1;

            $makeQueueEndTime = $this->addTimeInterval($trEndTime, $makeQueueCycleLength, $repeatTimes - 1) - $makeQueueOffsetToEnd;
            $processQueueEndTime = $this->addTimeInterval($trEndTime, $processQueueCycleLength, $repeatTimes - 1) - $processQueueOffsetToEnd;
            $queueCycleEndTime = $this->addTimeInterval($trEndTime, $trCycleLength, $repeatTimes - 1);

            //update queueline status to expired once time exceed all of end time
            if (time() > $makeQueueEndTime && time() > $processQueueEndTime && time() > $queueCycleEndTime) {
                $mServiceQL = BMAppOnlineQueueServiceQueueLine::model()->findByPk($queueLineId);
                $mServiceQL->status = BAQQueueLine::QueueLineStatus_Expired;
                $mServiceQL->save();
            }


            if ($makeQueueTime != NULL || $processQueueTime != NULL) {
                for ($i = 0; $i < $repeatTimes; $i++) {
                    $cycleEndTime = $this->subTimeInterval($trEndTime, $trCycleLength, $i);
                    $cycleStartTime = $this->subTimeInterval($trEndTime, $trCycleLength, $i + 1);
                    $makeQueueEndTime = $this->subTimeInterval($trEndTime, $makeQueueOffsetToEnd);
                    $makeQueueCycleStartTime = $this->subTimeInterval($makeQueueEndTime, $makeQueueCycleLength, $i + 1);
                    $makeQueueCycleEndTime = $this->subTimeInterval($makeQueueEndTime, $makeQueueCycleLength, $i);
                    $processQueueEndTime = $this->subTimeInterval($trEndTime, $processQueueOffsetToEnd);
                    $processQueueCycleStartTime = $this->subTimeInterval($processQueueEndTime, $processQueueCycleLength, $i + 1);
                    $processQueueCycleEndTime = $this->subTimeInterval($processQueueEndTime, $processQueueCycleLength, $i);
                    if ($makeQueueCycleStartTime < $makeQueueTime
                            && $makeQueueCycleEndTime > $makeQueueTime) {
                        $currentCycle['startTime'] = $cycleStartTime;
                        $currentCycle['endTime'] = $cycleEndTime;
                        $currentCycle['length'] = $trCycleLength;
                        $currentCycle['makeQueueStartTime'] = $makeQueueCycleStartTime;
                        $currentCycle['makeQueueLength'] = $makeQueueCycleLength;
                        $currentCycle['makeQueueEndTime'] = $makeQueueCycleEndTime;
                        $currentCycle['processQueueStartTime'] = $processQueueCycleStartTime;
                        $currentCycle['processQueueEndTime'] = $processQueueCycleEndTime;
                        $currentCycle['processQueueLength'] = $processQueueCycleLength;
                        array_push($activeCycles, $currentCycle);
                    }

                    if ($processQueueCycleStartTime < $processQueueTime
                            && $processQueueCycleEndTime > $processQueueTime) {
                        $currentCycle['startTime'] = $cycleStartTime;
                        $currentCycle['endTime'] = $cycleEndTime;
                        $currentCycle['length'] = $trCycleLength;
                        $currentCycle['makeQueueStartTime'] = $makeQueueCycleStartTime;
                        $currentCycle['makeQueueLength'] = $makeQueueCycleLength;
                        $currentCycle['makeQueueEndTime'] = $makeQueueCycleEndTime;
                        $currentCycle['processQueueStartTime'] = $processQueueCycleStartTime;
                        $currentCycle['processQueueEndTime'] = $processQueueCycleEndTime;
                        $currentCycle['processQueueLength'] = $processQueueCycleLength;
                        array_push($activeCycles, $currentCycle);
                    }
                }
            }

            if ($resources != NULL && is_array($resources)) {
                foreach ($resources as $resource) {
                    foreach ($activeCycles as $currentCycle) {
                        $resourceId = $resource->id;
                        $cycleStartTime = isset($currentCycle['startTime']) ? $currentCycle['startTime'] : -1;
                        $cycleEndTime = isset($currentCycle['endTime']) ? $currentCycle['endTime'] : -1;
                        $sql = "select * from bln_app_onlinequeue_service_queueline_transaction where service_queueline_resource_id = :ResourceId 
                and (start_time = :StartTime or end_time = :EndTime)";
                        $params = array(':ResourceId' => $resourceId,
                            ':StartTime' => isset($currentCycle['startTime']) ? $currentCycle['startTime'] : -1,
                            ':EndTime' => isset($currentCycle['endTime']) ? $currentCycle['endTime'] : -1,);
                        $transaction = BMServiceQueueLineTransaction::model()->findBySql(
                                $sql, $params);

                        /* if transaction not exist, create it */
                        if ($transaction == NULL) {
                            $offsetToStartTime = $cycleStartTime - $trStartTime;
                            $tmpCycleLength = strtotime('+' . $trCycleLength) - time();
                            $sequence = $offsetToStartTime / $tmpCycleLength;
                            $transaction = $this->addQueueLineTransaction($resourceId, $cycleStartTime, $cycleEndTime, $sequence);
                        }

                        array_push($activeTransactions, $transaction);
                    }
                }
            }
        }

        return array('currentTransactions' => $activeTransactions, 'currentCycles' => $activeCycles);
    }

    protected function addTransactionQueue($queueLine, $makeQueueTime, $resource = array(), $timeResource = array(), $queueMaker = array()) {
        $queueMakerId = isset($queueMaker['id']) ? $queueMaker['id'] : NULL;

        $transaction = $this->findTransaction($queueLine, $resource, $timeResource, array('makeQueueTime' => $makeQueueTime));

        $maxQueueNumber = BMServiceQueueLineTransactionQueue::model()->findBySql(
                'select max(queue_number) as maxQueueNumber from bln_app_onlinequeue_service_queueline_transaction_queue 
                    where transaction_id = :TransactionId ', array(':TransactionId' => $transaction->_id));

        $newTransQueueModel = new BMServiceQueueLineTransactionQueue();
        $newTransQueueModel->transaction_id = $transaction->_id;
        $newTransQueueModel->queue_member_id = $queueMakerId;
        $newTransQueueModel->queue_number = $maxQueueNumber + 1;

        $newTransQueueModel->save();

        return $newTransQueueModel;
    }

    /* expression of w2{d[1~5]{h[9~18]},d[6]{h[9~13]},d[7]{h[9~11]}}
     * format of timePeriod: 
     * array('unit'=>'week','length'=2,
     * array('unit'=>day,'indexList'=>[1~5],array('unit'=>hour,'indexList'=>"9~18")),
     * array('unit'=>day,'indexList =>[6,7])
     * )
     */

    private function parsePeriodExpression($str, &$childPeriod = array()) {

        //$period = array();

        $matches = array();

        //$parentPeriod = array();
        //match to format like m2{...}
        $pattern = '/^(.*?)[\{](.*)[\}]/';

        $mResult = preg_match($pattern, $str, $matches);

        if (isset($matches[1])) {
            $period1 = array();
            $period2 = array();
            $this->parsePeriod($matches[1], $period1);

            if (isset($matches[2])) {
                $mts = explode(";", $matches[2]);

                foreach ($mts as $m) {
                    //$parsedFlag = TRUE;
                    $childPeriod = array();
                    $this->parsePeriodExpression($m, $childPeriod);

                    if (preg_match($pattern, $m) == 0) {
                        $this->parsePeriod($m, $period2);
                        if ($period2 != NULL)
                            array_push($period1, $period2);
                    } else {
                        if ($childPeriod != NULL)
                            array_push($period1, $childPeriod);
                    }
                }
                //array_push($parentPeriod, $childPeriod);
            }

            if ($period1 != NULL)
                $childPeriod = $period1;
        }
        else {
            $this->parsePeriod($str, $childPeriod);
        }
    }

    private function parsePeriod($str, &$period = array()) {

        $periods = array();

        //match to eigher of y or q,M,w,d,h,m
        $pattern = "/^([yqMwdhm])/";
        //match to w7, h5 and so on;
        $pattern1 = "/^([yqMwdhm])(\d+)/";
        //match to format like h[1,3,5] or d[1~5]
        $pattern2 = "/^([yqMwdhm])([\[](.*?)[\]])/";

        $result = preg_match($pattern, $str, $matches);
        $result1 = preg_match($pattern1, $str, $matches1);
        $result2 = preg_match($pattern2, $str, $matches2);

        if ($result === 1) {
            if ($str == 'M') {
                $period['unit'] = 'month';
                //$period['length'] = '1';
            }
            if ($str == 'w') {
                $period['unit'] = 'week';
            }
            if ($str == 'd') {
                $period['unit'] = 'day';
            }
            if ($str == 'h') {
                $period['unit'] = 'hour';
            }
            if ($str == 'm') {
                $period['unit'] = 'minute';
            }
            if ($str == 's') {
                $period['unit'] = 'second';
            }
        }

        if ($result1 === 1) {
            $this->parsePeriod($matches1[1], $period);
            //$period['unit']= $matches[1];
            $period['length'] = $matches1[2];
        }

        if ($result2 === 1) {
            $this->parsePeriod($matches2[1], $period);
            //$period['unit']= $matches[1];
            $period['indexList'] = $matches2[2];
        }
    }

    private function parsePeriodLength($period) {

        $lengthValue = isset($period['length']) ? $period['length'] : 1;

        $length = isset($period['unit']) ? ($lengthValue > 1 ? $lengthValue . ' ' . $period['unit'] . 's' : $lengthValue . ' ' . $period['unit']) : NULL;

        return $length;
    }

    private function addTimeInterval($dateTime, $interval, $intervalRepeat = 1) {

        if ($interval == NULL || $interval == '0' || $interval == 0)
            return $dateTime;

        if ($intervalRepeat == '0' || $intervalRepeat == 0)
            return $dateTime;

        $endTime = $dateTime;

        if ($intervalRepeat > 0) {
            for ($i = 0; $i < $intervalRepeat; $i++) {
                $endTime = strtotime('+ ' . $interval, $endTime);
            }
        }

        if ($endTime != NULL)
            return $endTime;
        return FALSE;
    }

    private function subTimeInterval($dateTime, $interval, $intervalRepeat = 1) {

        if ($interval == NULL || $interval == '0' || $interval == 0)
            return $dateTime;

        if ($intervalRepeat == '0' || $intervalRepeat == 0)
            return $dateTime;

        $endTime = $dateTime;

        if ($intervalRepeat > 0) {
            for ($i = 0; $i < $intervalRepeat; $i++) {
                $endTime = strtotime('- ' . $interval, $endTime);
            }
        }

        if ($endTime != NULL)
            return $endTime;
        return FALSE;
    }

    private function formatDateTimeIntoInteger($timeData = array('startTime' => null, 'length' => null, 'endTime' => null, 'lengthRepeat' => 1)) {

        $intData = array();

        $startTimeString = $timeData['startTime'] == NULL ? NULL : date(DATE_ATOM, $timeData['startTime']);
        $lengthString = $timeData['length'];
        $lengthRepeat = $timeData['lengthRepeat'];
        $endTimeString = $timeData['endTime'] == NULL ? NULL : date(DATE_ATOM, $timeData['endTime']);

        if ($lengthString != NULL) {
            $templength = explode('*', $lengthString);
            $interval = is_numeric($templength[0]) ? $templength[0] * $lengthRepeat : '';

            if ($templength[1] == 'year') {
                $interval = 'P' . $interval . 'Y';
            }
            if ($templength[1] == 'quarter') {
                $interval = 'P' . $interval * 4 . 'M';
            }
            if ($templength[1] == 'month') {
                $interval = 'P' . $interval . 'M';
            }
            if ($templength[1] == 'week') {
                $interval = 'P' . $interval * 7 . 'D';
            }
            if ($templength[1] == 'day') {
                $interval = 'P' . $interval . 'D';
            }

            if ($templength[1] == 'hour') {
                $interval = 'PT' . $interval . 'H';
            }

            if ($templength[1] == 'minute') {
                $interval = 'PT' . $interval . 'M';
            }

            if ($startTimeString != null && $endTimeString == NULL) {
                $date = new DateTime($startTimeString);
                //$interval = $templength[0] * $lengthRepeat;
                //$interval = 'P' . $interval . $timeUnit;
                $endTimeString = $date->add(new DateInterval($interval));
            }
            if ($startTimeString == null && $endTimeString != NULL) {
                $date = new DateTime($endTimeString);
                //$interval = $templength[0] * $lengthRepeat;
                //$interval = 'P' . $interval . $timeUnit;
                $endTimeString = $date->sub(new DateInterval($interval));
            }

            $intData['startTime'] = strtotime($startTimeString);
            $intData['endTime'] = strtotime($endTimeString);
            $intData['length'] = $intData['endTime'] = $intData['startTime'];

            return $intData;
        }

        return FALSE;
    }

    /* expression of w2{d[1~5]{h[9~18]},d[6]{h[9~13]},d[7]{h[9~11]}}
     * format of timePeriod: 
     * array('unit'=>'week','length'=2,
     * array('unit'=>day,'indexList'=>[1~5],array('unit'=>hour,'indexList'=>"9~18")),
     * array('unit'=>day,'indexList =>[6,7])
     * )
     */

    private function parsePeriodIntoPieces($period = array(), &$phases = array(), $length = '', $startTime = '') {

        $containArray = FALSE;
        $startTime2 = $startTime;

        if (isset($period['unit']) && !isset($period['length']) && !isset($period['indexList']))
            $period['length'] = 1;

        if (isset($period['length'])) {
            for ($i = 0; $i < $period['length']; $i++) {
                if ($i != 0)
                    $startTime2 = $this->getTimeLengthAccordingTimeUnit($period['unit'], $i, $startTime);
                foreach ($period as $item) {
                    if (is_array($item)) {
                        $containArray = TRUE;
                        $this->parsePeriodIntoPieces($item, $phases, $period['unit'], $startTime);
                    }
                }
                if (!$containArray) {
                    array_push($phases, array('startTime' => $startTime2, 'length' => $period['unit']));
                }
            }
        }

        if (isset($period['indexList'])) {
            $pattern = "/(\d+)~(\d+)/";

            $result = preg_match($pattern, $period['indexList'], $matches);

            if ($result == 1) {
                $startTime = $this->getTimeLengthAccordingTimeUnit($period['unit'], $matches[1], $startTime);
                $parentStartTime = $startTime;
                $length = $this->getTimeLengthAccordingTimeUnit($period['unit'], intval($matches[2]) - intval($matches[1]));
                $lengthVal = intval($matches[2]) - intval($matches[1]);
                foreach ($period as $item) {
                    if (is_array($item)) {
                        $containArray = TRUE;
                        //for each sub item, divide into pieces to add subitems
                        for ($i = 0; $i < $lengthVal + 1; $i++) {
                            if ($i != 0)
                                $startTime = $this->getTimeLengthAccordingTimeUnit($period['unit'], $i, $parentStartTime);
                            $this->parsePeriodIntoPieces($item, $phases, $length, $startTime);
                        }
                    }
                }

                if (!$containArray) {
                    array_push($phases, array('startTime' => $startTime, 'length' => $length));
                }
            }

            $pattern = "/\d+[,]\d+/";
            $result = preg_match($pattern, $period['indexList'], $matches);

            if ($result == 1) {
                // $digs = explode(",", $period['indexList']);
                $result = preg_match('/\[(\d+),(\d+)\]/', $period['indexList'], $matches);
                //$digs = array($matches[1]);
                if ($result == 1) {
                    $digs = $matches;
                    unset($digs[0]);
                    foreach ($digs as $dig) {
                        $startTime2 = $this->getTimeLengthAccordingTimeUnit($period['unit'], $dig, $startTime);
                        $length = $this->getTimeLengthAccordingTimeUnit($period['unit'], 1);
                        foreach ($period as $item) {
                            if (is_array($item)) {
                                $containArray = TRUE;
                                $this->parsePeriodIntoPieces($item, $phases, $length, $startTime2);
                            }
                        }

                        if (!$containArray) {
                            array_push($phases, array('startTime' => $startTime2, 'length' => $length));
                        }
                    }
                }
            }
        }
    }

    private function getTimeLengthAccordingTimeUnit($timeUnit, $repeatTime = NULL, $initLength = NULL) {

        if ($repeatTime == NULL)
            $repeatTime = 1;

        $matches = array();
        $initDateLength = 'P';
        $initTimeLength = 'PT';

        if ($initLength == NULL || $initLength == '') {
            // $initDateLength = 'P';
            // $initTimeLength = 'PT';
        } else {
            if (preg_match('/(P\d+.*)(PT\d+.*)/', $initLength, $matches) === 1) {
                $initDateLength = $matches[1];
                $initTimeLength = $matches[2];
            } else {
                if (preg_match('/^(PT\d+.*)/', $initLength, $matches) === 1) {
                    $initTimeLength = $matches[1];
                }
                if (preg_match('/^(P\d+.*)/', $initLength, $matches) === 1) {
                    $initDateLength = $matches[1];
                }
            }
        }

        if ($timeUnit == 'year') {
            $matchResult = preg_match('/((\d+)[yY])/', $initDateLength, $matches);
            if ($matchResult == 1) {
                $replaceValue = intval($matches[2]) + $repeatTime;
                $initDateLength = str_replace($matches[1], $replaceValue . 'Y', $initDateLength);
            } else {
                $initDateLength = $initDateLength . $repeatTime . 'Y';
            }
        }
        if ($timeUnit == 'month') {
            $matchResult = preg_match('/((\d+)[M])/', $initDateLength, $matches);
            if ($matchResult == 1) {
                $replaceValue = intval($matches[2]) + $repeatTime;
                $initDateLength = str_replace($matches[1], $replaceValue . 'M', $initDateLength);
            } else {
                $initDateLength = $initDateLength . $repeatTime . 'M';
            }
        }
        if ($timeUnit == 'week') {
            $matchResult = preg_match('/((\d+)[Dd])/', $initDateLength, $matches);
            if ($matchResult == 1) {
                $replaceValue = intval($matches[2]) + 7 * $repeatTime;
                $initDateLength = str_replace($matches[1], $replaceValue . 'D', $initDateLength);
            } else {
                $initDateLength = $initDateLength . 7 * $repeatTime . 'D';
            }
        }
        if ($timeUnit == 'day') {
            $matchResult = preg_match('/((\d+)[D])/', $initDateLength, $matches);
            if ($matchResult == 1) {
                $replaceValue = intval($matches[2]) + $repeatTime;
                $initDateLength = str_replace($matches[1], $replaceValue . 'D', $initDateLength);
            } else {
                $initDateLength = $initDateLength . $repeatTime . 'D';
            }
        }
        if ($timeUnit == 'hour') {
            $matchResult = preg_match('/((\d+)[Hh])/', $initTimeLength, $matches);
            if ($matchResult == 1) {
                $replaceValue = intval($matches[2]) + $repeatTime;
                $initTimeLength = str_replace($matches[1], $replaceValue . 'H', $initTimeLength);
            } else {
                $initTimeLength = $initTimeLength . $repeatTime . 'H';
            }
        }
        if ($timeUnit == 'minute') {
            $matchResult = preg_match('/((\d+)[Mn])/', $initTimeLength, $matches);
            if ($matchResult == 1) {
                $replaceValue = intval($matches[2]) + $repeatTime;
                $initDateLength = str_replace($matches[1], $replaceValue . 'M', $initTimeLength);
            } else {
                $initTimeLength = $initTimeLength . $repeatTime . 'M';
            }
        }

        $length = $initDateLength == 'P' ? '' : $initDateLength;
        $length = $initTimeLength == 'PT' ? $length : $length . $initTimeLength;

        return $length;
    }

    private function insertTimeResource($data) {

        $insertSql = "insert bln_app_onlinequeue_service_queueline_timeresource( 
            allocate_queue_strategy,service_queueline_id,start_time,end_time,
            cycle_length,cycle_period,cycle_repeat_times,timeslot_length,
            makequeue_offset_to_endtime,makequeue_cycle_length,makequeue_cycle_period,
            processqueue_offset_to_endtime,processqueue_cycle_length,processqueue_cycle_period,
            data )values( 
            :Strategy,:QLineId,:StartTime,:EndTime,
            :CycleLength,:CyclePeriod,:CycleRepeat,:TimeSlotLength,
            :MQueueOffset,:MQueueLength,:MQueuePeriod,
            :PQueueOffset,:PQueueLength,:PQueuePeriod,:Data)";


        $conn = $this->getConnection();

        $insertCmd = $conn->createCommand($insertSql);
        $insertCmd->bindParam(":Strategy", $data['strategy'], PDO::PARAM_STR);
        $insertCmd->bindParam(":QLineId", $data['qLineId'], PDO::PARAM_INT);
        $insertCmd->bindParam(":StartTime", $data['startTime'], PDO::PARAM_INT);
        $insertCmd->bindParam(":EndTime", $data['endTime'], PDO::PARAM_INT);
        $insertCmd->bindParam(":CycleLength", $data['cycleLength'], PDO::PARAM_STR);
        $insertCmd->bindParam(":CyclePeriod", $data['cyclePeriod'], PDO::PARAM_STR);
        $insertCmd->bindParam(":CycleRepeat", $data['cycleRepeatTimes'], PDO::PARAM_INT);
        $insertCmd->bindParam(":TimeSlotLength", $data['timeSlotLength'], PDO::PARAM_STR);
        $insertCmd->bindParam(":MQueueOffset", $data['mQueueOffset'], PDO::PARAM_STR);
        $insertCmd->bindParam(":MQueueLength", $data['mQueueLength'], PDO::PARAM_STR);
        $insertCmd->bindParam(":MQueuePeriod", $data['mQueuePeriod'], PDO::PARAM_STR);
        $insertCmd->bindParam(":PQueueOffset", $data['pQueueOffset'], PDO::PARAM_STR);
        $insertCmd->bindParam(":PQueueLength", $data['pQueueLength'], PDO::PARAM_STR);
        $insertCmd->bindParam(":PQueuePeriod", $data['pQueuePeriod'], PDO::PARAM_STR);
        $insertCmd->bindParam(":Data", $data['data'], PDO::PARAM_STR);
        $insertCmd->execute();
    }

}

?>
